﻿using System;
using jade.core;
using jade.core.behaviours;
using jade.lang.acl;
using jade.domain.FIPAAgentManagement;
using jade.domain;
using jade.content;
using log4net;
using jade.content.lang;
using jade.content.onto;
using Agents.ontology;
using jade.content.lang.sl;
using jade.content.lang.leap;
using GatewayUtil.RequestResponse;
using Action = jade.content.onto.basic.Action;
using GatewayUtil.gatewayConfig;

namespace Agents
{
    class CalculatorAgent:Agent
    {
        protected static readonly ILog log = LogManager.GetLogger(typeof(CalculatorAgent));
        private Codec codec = new LEAPCodec();
        private Ontology ontology = CalculatorOntology.getInstance();

        public override void setup()
        {
            
            log.Debug("Start Agent with name: "+this.getLocalName());
            getContentManager().registerLanguage(codec);
            getContentManager().registerOntology(ontology);

            this.getContentManager().setValidationMode(false);

            addBehaviour(new ReceiverBehaviour(this));

            ServiceDescription sd = new ServiceDescription();
            sd.setName(this.getLocalName());
            sd.setType("CalculatorAgent");
            sd.addOntologies(ontology.getName());


            sd.addProperties(new Property(GWConst.PUBLIC_AS_WEBSERVICE, true));
            sd.addProperties(new Property(GWConst.OPERATION, "CalculatorOntology.Agents.Sum"));
            sd.addProperties(new Property(GWConst.OPERATION, "CalculatorOntology.Agents.Multiply"));
                     

            DFAgentDescription dfad = new DFAgentDescription();
            dfad.setName(this.getAID());
            dfad.addServices(sd);
            DFService.register(this, dfad);
            
        }
        private void debug(string p)
        {
            log.Debug(this.getLocalName() + ": " + p);

        }
        private void error(string p)
        {
            log.Error(this.getLocalName() + ": " + p);

        }
        private void error(object p)
        {
            log.Error(this.getLocalName() + ": " + p);

        }

        public override void takeDown()
        {
            base.takeDown();
            try{
                DFService.deregister(this);
            }catch(FIPAException e){
                error(e);
            }

        }

        class ReceiverBehaviour:CyclicBehaviour
        {
            private Codec codec = new LEAPCodec();
            private Ontology ontology = CalculatorOntology.getInstance();
            private MessageTemplate template = MessageTemplate.MatchOntology(CalculatorOntology.getInstance().getName());
            public ReceiverBehaviour(Agent a)
                : base(a)
            {

            }

            public override void action()
            {
                
                try
                {
                    ((CalculatorAgent)this.myAgent).debug("receiver: waiting for message");
                    ACLMessage msg = this.myAgent.receive(template);
                    if (msg != null)
                    {
                        
                        Action action = (Action)this.myAgent.getContentManager().extractContent(msg);
                        AgentAction agentAction = (AgentAction)action.getAction();
                        CalculatorResult calculResult = null;

                        if (agentAction is Sum)
                        {
                            calculResult = sumOperation((Sum)agentAction);
                        }
                        else if (agentAction is Multiply)
                        {
                            calculResult = multiplyOpleration((Multiply)agentAction);
                        }
                        else
                        {
                            // error state
                            log.Error("AgentAction is not valid, its type is " + agentAction.GetType().FullName);
                        }

                        jade.content.onto.basic.Result result = new jade.content.onto.basic.Result(action, calculResult);
                        ContentElement content = result;
                        
                        ACLMessage reply = msg.createReply();
                        reply.setPerformative(ACLMessage.INFORM);
                        this.myAgent.getContentManager().fillContent(reply, content);
                        
                        reply.addUserDefinedParameter(ACLMessage.IGNORE_FAILURE, "true");

                        ((CalculatorAgent)this.myAgent).debug("I'm sending response");
                        this.myAgent.send(reply);
                        ((CalculatorAgent)this.myAgent).debug("I've sent back the message");

                    }
                    else block();
                }
                catch (Exception e)
                {
                    ((CalculatorAgent)this.myAgent).error(e);
                    throw e;
                }
            }

            private CalculatorResult multiplyOpleration(Multiply multiply)
            {
                log.Debug("Multiply operation");

                CalculatorResult result = new CalculatorResult();
                result.result = multiply.a * multiply.b;
                return result;
            }

            private CalculatorResult sumOperation(Sum sumAction)
            {
                log.Debug("SUM operation");

                CalculatorResult result = new CalculatorResult();
                result.result = sumAction.a + sumAction.b;
                return result;
            }

        }

    }
}
